package cn.bby.tools.dialog;

import cn.bby.tools.dialog.common.BaseFieldParseDialog;
import cn.bby.tools.component.FieldParseComponent;
import cn.bby.tools.service.StateManagementService;
import cn.bby.tools.utils.ClassChooseUtil;
import cn.bby.tools.utils.ClipboardUtil;
import cn.bby.tools.utils.FieldUtil;
import cn.bby.tools.utils.MessageUtil;
import cn.hutool.core.util.StrUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.ValidationInfo;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiModifier;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.ui.DocumentAdapter;
import com.intellij.util.ui.JBUI;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import javax.swing.border.LineBorder;
import javax.swing.event.DocumentEvent;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 字段对比对话框
 * 用于将选中的字符串与类字段进行对比
 *
 * @author ben
 * @version 1.0
 */
public class FieldCompareDialog extends BaseFieldParseDialog {
    private static final FieldCompareDialog.FieldCompareState state = StateManagementService.getInstanceState().fieldCompareState;

    protected final FieldParseComponent targetParseUi;
    private PsiClass selectedClass;
    private final Project project;
    private JTextField classField;
    private final LinkedHashMap<String, String> matchFields = new LinkedHashMap<>();

    // 新增组件
    private JTabbedPane tabbedPane;
    private static final int CLASS_TAB_INDEX = 0;
    private static final int TEXT_TAB_INDEX = 1;

    @Override
    protected @NotNull Action @NotNull [] createActions() {
        // 创建自定义按钮：复制并关闭 和 关闭
        DialogWrapperAction copyAndCloseAction = new DialogWrapperAction(MessageUtil.getMessage("message.CopyAndCloseByCol")) {
            @Override
            protected void doAction(ActionEvent e) {
                if (isValidError()) {
                    return;
                }
                if (matchFields.isEmpty()) {
                    ClipboardUtil.setTextToClipboard("");
                } else {
                    ClipboardUtil.copyAsColumnSelection(new ArrayList<>(matchFields.values()));
                }
                JButton button = getButton(this);
                if (button != null) {
                    JBPopupFactory.getInstance().createMessage(MessageUtil.getMessage("message.CopiedSuccess"))
                            .showUnderneathOf(button);
                }
            }
        };
        DialogWrapperAction copyAndCloseActionAndClose = new DialogWrapperAction(
                MessageUtil.getMessage("message.CopyAndCloseByColAndClose")) {
            @Override
            protected void doAction(ActionEvent e) {
                if (isValidError()) {
                    return;
                }
                saveState();
                doCopyAndCloseAction();
            }
        };

        DialogWrapperAction closeAction = new DialogWrapperAction(MessageUtil.getMessage("message.Close")) {
            @Override
            protected void doAction(ActionEvent e) {
                saveState();
                doCancelAction();
            }
        };

        return new Action[]{copyAndCloseAction, copyAndCloseActionAndClose, closeAction};
    }

    @Override
    protected void doCopyAndCloseAction() {
        if (matchFields.isEmpty()) {
            ClipboardUtil.setTextToClipboard("");
        } else {
            ClipboardUtil.copyAsColumnSelection(new ArrayList<>(matchFields.values()));
        }
        close(OK_EXIT_CODE);
    }

    @Override
    public void saveState() {
        state.selectedText = sourceParseUi.getSourceText();
        state.selFormatOptId = sourceParseUi.getFormatOpt();

        state.targetText = targetParseUi.getSourceText();
        state.targetFormatOptId = targetParseUi.getFormatOpt();

        state.selectedClass = classField.getText();
        // 保存当前选中的tab索引
        state.tabIndex = tabbedPane.getSelectedIndex();
    }

    @Override
    public void loadState() {
        if (StrUtil.isBlank(sourceParseUi.getSourceText())) {
            // 恢复目标文本内容
            sourceParseUi.setSourceText(state.selectedText);
            sourceParseUi.setFormatOpt(state.selFormatOptId);
            sourceParseUi.updateParsedFields();
        }
        classField.setText(state.selectedClass);
        setLastSelectedClass(state.selectedClass);
        // 恢复之前选中的tab
        if (state.tabIndex >= 0 && state.tabIndex < tabbedPane.getTabCount()) {
            tabbedPane.setSelectedIndex(state.tabIndex);
        }
        // 恢复目标文本解析选项
        targetParseUi.setSourceText(state.targetText);
        targetParseUi.setFormatOpt(state.targetFormatOptId);
        // 更新目标解析字段显示
        targetParseUi.updateParsedFields();
    }

    /**
     * 构造函数
     *
     * @param project      项目实例
     * @param selectedText 选中的文本
     */
    public FieldCompareDialog(@Nullable Project project, String selectedText) {
        super(project, MessageUtil.getMessage("action.BBY.FieldCompareAction.text"));
        this.project = project;
        // 将 String 类型的 selectedText 设置到 JTextArea 中
        this.sourceParseUi.setSourceText(selectedText);
        this.targetParseUi = new FieldParseComponent("message.TargetText");
        init();
        setModal(false);
    }

    @Override
    protected @Nullable JComponent createCenterPanel() {
        JPanel panel = new JPanel(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = JBUI.insets(5);
        gbc.anchor = GridBagConstraints.WEST;

        // 初始化组件
        initializeFields();

        // 创建滚动面板
        JScrollPane resultScrollPane = new JScrollPane(resultTextArea);
        resultScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
        resultScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);

        // 添加源文本解析面板（带边框和标题）
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.gridwidth = 3;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.weightx = 1.0;
        JPanel sourcePanel = new JPanel(new BorderLayout());
        sourcePanel.setBorder(BorderFactory.createTitledBorder(LineBorder.createGrayLineBorder(), MessageUtil.getMessage("message.SourceText")));
        sourcePanel.add(sourceParseUi, BorderLayout.CENTER);
        panel.add(sourcePanel, gbc);

        // 创建 tab 面板
        tabbedPane = new JTabbedPane();
        JPanel classPanel = createClassPanel();
        tabbedPane.addTab(MessageUtil.getMessage("message.SelectClass"), classPanel);
        tabbedPane.addTab(MessageUtil.getMessage("message.InputText"), targetParseUi);


        gbc.gridy = 1;
        gbc.weighty = 0;
        gbc.fill = GridBagConstraints.BOTH;
        JPanel tabbedPanel = new JPanel(new BorderLayout());
        tabbedPanel.setBorder(BorderFactory.createTitledBorder(LineBorder.createGrayLineBorder(), MessageUtil.getMessage("message.TargetText")));
        tabbedPanel.add(tabbedPane, BorderLayout.CENTER);
        panel.add(tabbedPanel, gbc);

        // 添加结果显示区域（带边框和标题）
        gbc.gridy = 2;
        gbc.gridwidth = 3;
        gbc.fill = GridBagConstraints.BOTH;
        gbc.weightx = 1.0;
        JButton compareButton = new JButton("↓↓  " + MessageUtil.getMessage("message.Compare") + "  ↓↓");
        panel.add(compareButton, gbc);
        gbc.gridy = 3;
        gbc.weighty = 1.0;
        JPanel resultPanel = new JPanel(new BorderLayout());
        resultPanel.setBorder(BorderFactory.createTitledBorder(LineBorder.createGrayLineBorder(), MessageUtil.getMessage("message.Result")));
        resultPanel.add(resultScrollPane, BorderLayout.CENTER);
        panel.add(resultPanel, gbc);

        compareButton.addActionListener(e -> updateResults());
        // 添加事件监听器
        addEventListeners();

        loadState();
        return panel;
    }

    /**
     * 创建类对比面板
     */
    private JPanel createClassPanel() {
        JPanel panel = new JPanel(new GridBagLayout());
        panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = JBUI.insets(5);
        gbc.anchor = GridBagConstraints.WEST;

        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.gridwidth = 1;
        gbc.weightx = 0;
        gbc.fill = GridBagConstraints.NONE;
        panel.add(new JLabel(MessageUtil.getMessageSuffix("message.TargetClass")), gbc);

        gbc.gridx = 0;
        gbc.gridy = 1;
        gbc.weightx = 1.0;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        panel.add(classField, gbc);

        gbc.gridx = 1;
        gbc.weightx = 0;
        gbc.fill = GridBagConstraints.NONE;
        JButton selectClassButton = new JButton(MessageUtil.getMessage("message.SelectClass", "..."));
        panel.add(selectClassButton, gbc);

        selectClassButton.addActionListener(e -> selectClass());

        return panel;
    }

    /**
     * 初始化字段
     */
    private void initializeFields() {
        classField = new JTextField(30);
        classField.setEditable(false);
        resultTextArea.setEditable(false);
        resultTextArea.setBorder(BorderFactory.createLoweredBevelBorder());
        resultTextArea.setColumns(100);
        //自动换行
        resultTextArea.setLineWrap(true);
    }

    /**
     * 添加事件监听器
     */
    private void addEventListeners() {
        // 添加文本框内容变化监听器
        sourceParseUi.addDocumentListener(new DocumentAdapter() {
            @Override
            protected void textChanged(@NotNull DocumentEvent e) {
                updateResults();
            }
        });
        targetParseUi.addDocumentListener(new DocumentAdapter() {
            @Override
            protected void textChanged(@NotNull DocumentEvent e) {
                updateResults();
            }
        });

        // 添加标签页切换监听器
        tabbedPane.addChangeListener(e -> updateResults());
    }

    /**
     * 解析目标字符串为列
     *
     * @return 列名列表
     */
    protected List<String> parseTargetCols() {
        return targetParseUi.parseCols();
    }

    /**
     * 选择类
     */
    private void selectClass() {
        PsiClass selected = ClassChooseUtil.chooseClass(
                MessageUtil.getMessage("message.ChooseTarget"),
                project,
                selectedClass
        );
        if (selected != null) {
            selectedClass = selected;
            classField.setText(selected.getQualifiedName());
            updateResults();
        }
    }

    /**
     * 设置上次选中的类
     *
     * @param qualifiedName 类全限定名
     */
    private void setLastSelectedClass(String qualifiedName) {
        if (StrUtil.isBlank(qualifiedName)) {
            return;
        }
        GlobalSearchScope allScope = GlobalSearchScope.allScope(project);
        JavaPsiFacade facade = JavaPsiFacade.getInstance(project);
        PsiClass[] possibleClasses = facade.findClasses(qualifiedName, allScope);
        if (possibleClasses.length > 0) {
            selectedClass = possibleClasses[0];
            classField.setText(qualifiedName);
        }
    }

    /**
     * 更新结果
     */
    private void updateResults() {
        try {
            if (isValidError()) {
                return;
            }
            List<String> sourceFields = parseCols();
            Set<String> targetFields = getTargetCols();
            if (sourceFields.isEmpty()) {
                resultTextArea.setText("源文本中未解析出有效字段");
                return;
            }
            if (targetFields.isEmpty()) {
                if (tabbedPane.getSelectedIndex() == TEXT_TAB_INDEX) {
                    resultTextArea.setText("目标文本中未解析出有效字段");
                } else {
                    resultTextArea.setText("目标类中未找到匹配的字段");
                }
                return;
            }

            // 找出匹配的字段
            Map<String, String> matchFields = new HashMap<>();
            List<String> needFuzzyFields = new ArrayList<>();
            for (String sourceField : sourceFields) {
                if (targetFields.contains(sourceField)) {
                    matchFields.put(sourceField, sourceField);
                } else {
                    needFuzzyFields.add(sourceField);
                }
            }
            this.matchFields.clear();
            sourceFields.forEach(fieldName -> this.matchFields.put(fieldName, matchFields.get(fieldName)));
            if (!needFuzzyFields.isEmpty()) {
                // 模糊匹配
                List<FieldUtil.FieldRecord> fuzzyFields;
                if (tabbedPane.getSelectedIndex() == TEXT_TAB_INDEX) {
                    fuzzyFields = targetFields.stream()
                            .filter(targetField -> !matchFields.containsKey(targetField))
                            .map(targetField -> new FieldUtil.FieldRecord(Set.of(targetField), targetField, targetField.toLowerCase(Locale.ROOT)))
                            .toList();
                } else {
                    fuzzyFields = FieldUtil.getFuzzyFields(project, getTargetFields()
                        .stream().filter(f -> !matchFields.containsKey(f.getName())).toList());
                }
                List<FuzzyFieldScore> fuzzyFieldScores = new ArrayList<>(targetFields.size() * needFuzzyFields.size());
                for (String lossField : needFuzzyFields) {
                    for (FieldUtil.FieldRecord fuzzyField : fuzzyFields) {
                        double similarValue = 0;
                        for (String fuzzyName : fuzzyField.fuzzyNames()) {
                            double similar = StrUtil.similar(lossField.toLowerCase(Locale.ROOT), fuzzyName);
                            if (similar > similarValue) {
                                similarValue = similar;
                            }
                        }
                        if (similarValue > 0.3) {
                            fuzzyFieldScores.add(new FuzzyFieldScore(fuzzyField.fieldName(), lossField, similarValue));
                        }
                    }
                }
                fuzzyFieldScores.sort(Comparator.comparingDouble(FuzzyFieldScore::score).reversed());
                for (FuzzyFieldScore fuzzyFieldScore : fuzzyFieldScores) {
                    if (!StrUtil.isEmpty(this.matchFields.get(fuzzyFieldScore.matchName))) {
                        continue;
                    }
                    this.matchFields.put(fuzzyFieldScore.matchName, fuzzyFieldScore.fieldName);
                }
            }
            StringBuilder res = new StringBuilder(100);
            res.append("匹配结果（带*号的可能有误差）: \n");
            res.append(this.matchFields.entrySet().stream()
                    .map(e -> e.getKey() + ":" + (e.getKey().equals(e.getValue()) ? (e.getValue())
                            : (StrUtil.nullToEmpty(e.getValue()) + "*")))
                    .collect(Collectors.joining("\n")));
            res.append("\n\n未匹配项:\n");
            if (sourceFields.size() != matchFields.size()) {
                res.append(sourceFields.stream()
                        .filter(fieldName -> !matchFields.containsKey(fieldName))
                        .collect(Collectors.joining(",")));
            }
            res.append("\n\n多余项:\n");
            Set<String> matchedTarget = new HashSet<>(matchFields.values());
            res.append(targetFields.stream()
                    .filter(fieldName -> !matchedTarget.contains(fieldName))
                    .collect(Collectors.joining(","))
            );

            resultTextArea.setText(res.toString());
        } catch (
                Exception e) {
            resultTextArea.setText("处理出错: " + e.getMessage());
        }
    }


    private record FuzzyFieldScore(String fieldName, String matchName, double score) {

    }

    private Set<String> getTargetCols() {
        if (tabbedPane.getSelectedIndex() == TEXT_TAB_INDEX) {
            return new HashSet<>(parseTargetCols());
        }
        if (selectedClass != null) {
            return getTargetFields().stream().map(PsiField::getName).collect(Collectors.toSet());
        }
        return Collections.emptySet();
    }

    private List<PsiField> getTargetFields() {
        return Arrays.stream(selectedClass.getAllFields())
                .filter(f -> !f.hasModifierProperty(PsiModifier.STATIC))
                .toList();
    }

    /**
     * 字段对比状态
     */
    public static class FieldCompareState {
        public String selectedText = "";
        public int selFormatOptId = 1;

        public String targetText = "";
        public int targetFormatOptId = 1;

        public String selectedClass = "";
        public String targetClass = "";

        public int tabIndex = 0;
    }

    @Override
    protected @Nullable ValidationInfo doValidate() {
        ValidationInfo validationInfo = sourceParseUi.doValidate();
        if (validationInfo != null) {
            return validationInfo;
        }
        if (tabbedPane.getSelectedIndex() == TEXT_TAB_INDEX) {
            validationInfo = targetParseUi.doValidate();
        } else if (StrUtil.isEmpty(classField.getText())) {
            validationInfo = new ValidationInfo(MessageUtil.getMessage("message.SelectClassPlease"), classField);
        }
        if (validationInfo != null) {
            return validationInfo;
        }

        return super.doValidate();
    }
}